package com.mccken.annotation.processor;

import java.io.IOException;
import java.io.Writer;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

import com.google.auto.service.AutoService;
import com.mccken.annotation.McckenTag;

/**
 * 自定义注解处理器
 */
@AutoService(Processor.class)
public class CustomProcessor extends AbstractProcessor {

    private Filer mFiler;
    private Messager mMessager;
    private Elements mElementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFiler = processingEnvironment.getFiler();
        mMessager = processingEnvironment.getMessager();
        mElementUtils = processingEnvironment.getElementUtils();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotataions = new LinkedHashSet<String>();
        annotataions.add(McckenTag.class.getCanonicalName());
        return annotataions;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {

        mMessager.printMessage(Diagnostic.Kind.OTHER, ">>>>>>>>>>>>>>>>>>>>>> McckenTag start...");
        mMessager.printMessage(Diagnostic.Kind.OTHER, ">>>>>>>>>>>>>>>>>>>>>> McckenTag start2...");
        
        Set<? extends Element> tagElements = roundEnvironment.getElementsAnnotatedWith(McckenTag.class);
        for (Element element : tagElements) {
            // 1.获取包名
            PackageElement packageElement = mElementUtils.getPackageOf(element);
            String pkName = packageElement.getQualifiedName().toString();
            printMessage(String.format("package = %s", pkName));
            // 2.获取包装类类型
            TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
            String enclosingName = enclosingElement.getQualifiedName().toString();
            printMessage(String.format("enclosindClass = %s", enclosingName));
            // 3.获取注解的成员变量名
            String tagFiledName = element.getSimpleName().toString();
            // 4.获取注解的成员变量类型
            String tagFiledClassType = element.asType().toString();
            // 5.获取注解元数据
            McckenTag tag = element.getAnnotation(McckenTag.class);
            String name = tag.name();
            printMessage(String.format("%s %s = %s", tagFiledClassType, tagFiledName, name));
            // 6.生成文件
            createFile(enclosingElement, tagFiledClassType, tagFiledName, name);
            return true;
        }
        return false;
    }

    private void createFile(TypeElement enclosingElement, String tagFiledClassType, String tagFiledName, String name) {
        String pkName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
        try {
            JavaFileObject javaFileObject = mFiler.createSourceFile(pkName + ".Tag");
            Writer writer = javaFileObject.openWriter();
            writer.write(generateCode(pkName, tagFiledClassType, tagFiledName, name));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void printMessage(String msg) {
        mMessager.printMessage(Diagnostic.Kind.NOTE, msg);
    }

    private String generateCode(String pkName, String tagFiledClassType, String tagFiledName, String name) {
        StringBuilder builder = new StringBuilder();
        builder.append("package " + pkName + ";\n\n");
        builder.append("//Auto generated by apt,do not modify!!\n\n");
        builder.append("public class Tag { \n\n");
        builder.append("public void temp(){ \n");
        String info = String.format("%s %s = %s", tagFiledClassType, tagFiledName, name);
        builder.append("System.out.println(\"" + info + "\");\n");
        builder.append("}\n");
        builder.append("}");
        return builder.toString();
    }

}